<?php

namespace app\api\library;

use app\admin\model\CouponCodeCategory;
use app\admin\model\CouponCodeCities;
use app\admin\model\CouponCodeCombo;
use app\admin\model\CouponCodeGoods;
use app\admin\model\CouponCodeClass;
use app\admin\model\CouponCodeGoodsCategory;
use app\admin\model\CouponCodeOrderDetail;
use app\admin\model\CouponCodes;
use app\admin\model\CouponTo;
use app\admin\model\ImportType;
use app\common\model\User;
use app\api\controller\Couponlist;
use app\api\controller\Testd;
use app\api\controller\Testsand;
use EasyWeChat\Factory;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use think\Config;
use think\Db;
use think\exception\Handle;
use think\Request;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
use app\admin\model\Area;
use app\admin\model\CouponOrder;
use app\admin\model\Order;
use app\admin\model\OrderGoods;

/**
 * 自定义API模块的错误显示
 */
class ExceptionHandle extends Handle
{
    public function render(Exception $e)
    {
        // 在生产环境下返回code信息
        if (!\think\Config::get('app_debug')) {
            $statuscode = $code = 500;
            $msg        = 'An error occurred';
            // 验证异常
            if ($e instanceof \think\exception\ValidateException) {
                $code       = 0;
                $statuscode = 200;
                $msg        = $e->getError();
            }
            // Http异常
            if ($e instanceof \think\exception\HttpException) {
                $statuscode = $code = $e->getStatusCode();
            }
            return json(['code' => $code, 'msg' => $msg, 'time' => time(), 'data' => null], $statuscode);
        }

        //其它此交由系统处理
        return parent::render($e);
    }

    public static function is_domain($data)

    {
//        return !empty($domain) && strpos($domain, '--') === false && preg_match('/^([a-z0-9]+([a-z0-9-]*(?:[a-z0-9]+))?\.)?[a-z0-9]+([a-z0-9-]*(?:[a-z0-9]+))?(\.us|\.tv|\.org\.cn|\.org|\.net\.cn|\.net|\.mobi|\.me|\.la|\.info|\.hk|\.gov\.cn|\.edu|\.com\.cn|\.com|\.co\.jp|\.co|\.cn|\.cc|\.biz)$/i', $domain) ? true : false;
        $request = Request::instance();
        $domain  = $request->domain();
        if (substr($data, 0, 4) == 'http') {
            return $data;
        }
        return $domain . $data;
    }

    public static function order($userid, $goods_id)
    {
        $user     = User::where('id', $userid)->find();
        $goods    = CouponCodeGoods::where('id', $goods_id)->find();
        $order_no = date('YmdHis', time()) . str_pad($goods['id'], 5, 0, STR_PAD_LEFT) . rand(1000, 99999);//生成订单号

        //启动事务
        Db::startTrans();
        try {
            //如果是会员就用会员价不是会员就用非会员价  1 非会员 2 会员
            $pay_money = $user->is_member == 1 ? $goods->retail_price : $goods->price1;
            // \var_dump($pay_money);die;
            $data     = [
                'order_no'    => $order_no,
                'user_id'     => $userid,
                'user_mobile' => $user->username,
                'pay_money'   => $pay_money,
                'status'      => 1,
                'create_time' => time(),
                'end_time'    => time() + 30 * 24 * 3600,
            ];
            $order_id = Order::insertGetId($data);
            //添加订单商品表
            $goods_data = [
                'order_id'     => $order_id,
                'goods_id'     => $goods->id,
                'goods_name'   => $goods->name,
                'goods_code'   => $goods->goods_code,
                'goods_icon'   => $goods->icon,
                'goods_img'    => $goods->image,
                'price'        => $goods->price,
                'member_price' => $pay_money,
                'number'       => 1,
                'create_time'  => time(),
            ];
            OrderGoods::insert($goods_data);
            // 提交事务
            Db::commit();
            $res = $order_no;
        } catch (\Exception $e) {
            // \var_dump($e);
            // 回滚事务
            Db::rollback();
            $res = false;
        }
        return $res;
    }

    public function unifiedorder($openid, $out_trade_no, $total_fee, $notify_url, $body)
    {
        $wx_config  = Config::get('wx_config');
        $url        = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $parameters = [
            'appid'            => $wx_config['appid'], //小程序 ID
            'mch_id'           => $wx_config['mch_id'], //商户号
            'sub_mch_id'       => $wx_config['sub_mch_id'], //子商户号
            'nonce_str'        => $this->createNoncestr(), //随机字符串
            'body'             => $body,
            'out_trade_no'     => $out_trade_no,
            //            'total_fee' => floatval($total_fee * 100), //总金额 单位 分
            'total_fee'        => floatval(0.01 * 100), //总金额 单位 分
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], //终端 IP
            'notify_url'       => $notify_url, //通知地址  确保外网能正常访问
            'openid'           => $openid, //用户 id
            'trade_type'       => 'JSAPI'//交易类型
        ];
        //统一下单签名
        $parameters['sign'] = $this->getWxSign($parameters, $wx_config['mch_key']);
        $xmlData            = $this->arrayToXml($parameters);
        $return             = $this->xmlToArray($this->curlPost($url, $xmlData, 60));
        return $return;
    }

    //作用：产生随机字符串，不长于 32 位
    public function createNoncestr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str   = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    //数组转换成 xml
    public function arrayToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_array($val)) {
                $xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    //xml 转换成数组
    public function xmlToArray($xml)
    {
        //禁止引用外部 xml 实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val       = json_decode(json_encode($xmlstring), true);
        return $val;
    }

    //作用：生成签名
    public function getWxSign($Obj, $key)
    {
        foreach ($Obj as $k => $v) {
            $Parameters[$k] = $v;
        }
        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //签名步骤二：在 string 后加入 KEY
        $String = $String . "&key=" . $key;
        //签名步骤三：MD5 加密
        $String = md5($String);
        //签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        return $result_;
    }

    ///作用：格式化参数，签名过程需要使用
    public function formatBizQueryParaMap($paraMap, $urlencode)
    {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if ($urlencode) {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }


    public static function NotifyUrlStatus($order_no, $openid = '')
    {
        // $order_no = '202205261650200000391081';
        $order      = Order::where(['order_no' => $order_no])->find();
        $orderGoods = OrderGoods::where(['order_id' => $order['id']])->find();
        $update     = [
            'pay_status' => 1,
            'pay_time'   => time(),
        ];
        $result     = Order::where(['id' => $order['id']])->update($update);
        // $result = true;
        if ($result) {
            //把商品已售数量加1
            CouponCodeGoods::where(['id' => $orderGoods['goods_id']])->setInc('sales', $orderGoods['number']);
            //去调用福禄的充值接口   用鑫互助的商家
            $key          = 'tC34MVRPxzgqqhJXn7DBd1CEh2xs0RMv';
            $secret       = 'wQeRHoa0vXaMPvZB1653380665';
            $arr          = [
                'channel'   => $key,
                'timestamp' => time(),
                'goods_id'  => $orderGoods['goods_id'],
                'mobile'    => $order['user_mobile'],
                'exte_id'   => $order_no,
            ];
            $arr['sign']  = self::getSign($arr, $secret);
            $request      = Request::instance();
            $domain       = $request->domain();
            $url          = $domain . '/index.php/api/Opencoupon/recharge';
            $rechargeInfo = self::curl_json($url, json_encode($arr));
            $log          = [
                'order_no'   => $order_no,
                'content'    => $rechargeInfo,
                'createtime' => time(),
            ];
            //添加记录
            Db::name('record_log')->insert($log);
            $rechargeInfo = \json_decode($rechargeInfo, true);

            if ($rechargeInfo['code'] == 1 && $rechargeInfo['data']['status'] == 2) {
                //充值成功  修改充值数据
                $data = [
                    'status'        => 2,
                    'recharge_time' => time(),
                ];
                Order::where(['id' => $order['id']])->update($data);
                return true;
            } else {
                return false;
            }
        }

    }

    /**
     * 得到签名key
     * @param string $name
     * @return 签名key
     */
    public static function getKey($name)
    {
        $key = CouponTo::where('name', $name)->find();
        // var_dump($key);
        return $key;
    }

    /**
     * 生成签名
     * @param Array $param
     * @return 签名
     */
    public static function getSign($param, $app_secret = '')
    {
        //签名步骤一：按字典序排序参数
        ksort($param);
        $string = self::ToUrlParams($param);
        // var_dump($string);
        //签名步骤二：在string后加入KEY
        $string = $string . "&app_secret=" . $app_secret;
        //var_dump($string);
        //签名步骤三：MD5加密
        $string = md5($string);
        //var_dump($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        // var_dump($result);
        return $result;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public static function ToUrlParams($param)
    {
        $buff = "";
        foreach ($param as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 图片处理
     * @param 数组
     * @$field  字段名
     */
    public static function imgStr($param, $field)
    {

        $request = Request::instance();
        $domain  = $request->domain();

        if (is_array($param)) {
            foreach ($param as $k => $v) {
                $url               = parse_url($param[$k][$field]);
                $param[$k][$field] = $domain . $url['path'];
            }
        } else {
            foreach ($param[0]['data'] as $k => $v) {
                $param[0]['data'][$k]->$field = $domain . $param[0]['data'][$k]->$field;
            }
        }
        return $param;
    }

    /**
     * 二维数组去掉重复值
     * @$arr 数组
     * @$key  字段名
     */
    public static function second_array_unique_bykey($arr)
    {
        $tmp_arr = [];
        foreach ($arr as $k => $v) {
            if (in_array($v['id'], $tmp_arr)) {
                unset($arr[$k]);
            } else {
                $tmp_arr[$k] = $v['id'];
            }
        }
        return $arr;
    }

    /**
     * 核销记录
     * @$arr 数组
     * @$key  字段名
     */
    public static function verificationList($data)
    {

        $res = [];
        foreach ($data as $k => $v) {
            $brand  = User::where('id', $v->id)->field('username,avatar')->find();
            $img[0] = $brand;
            $brand  = self::imgStr($img, 'avatar');

            $order            = CouponCodeOrderDetail::where('user_id', $v->id)->where('status', 2)->field('id,mobile,up_time,user_id')->order('up_time desc')->select();
            $res[$k]['brand'] = $brand[0];
            $res[$k]['order'] = $order;
        }
        return $res;
    }

    /**
     * 发送post请求
     * @param string $url 请求地址
     * @param array $post_data post键值对数据
     * @return string
     */
    /*
     * curl
     * @param $jsondata 业务参数 json
     * @param $headerdata 系统参数 array
    */
    public static function curl_json($url, $jsondata)
    {
        $ch     = curl_init();
        $header = ['Content-Type: application/json;charset=UTF-8'];
        curl_setopt_array($ch, [
            CURLOPT_URL            => $url,
            CURLOPT_HTTPHEADER     => $header,
            CURLOPT_POST           => 1,
            CURLOPT_SSL_VERIFYPEER => FALSE,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_POSTFIELDS     => $jsondata
        ]);

        $data = curl_exec($ch);
        curl_close($ch);

        return $data;
    }

    public static function send_post($url, $post_data)
    {
        $postdata = http_build_query($post_data);

        $options = [

            'http' => [

                'method' => 'POST',

                'header' => 'Content-type:application/x-www-form-urlencoded',

                'content' => $postdata,

                'timeout' => 15 * 60 // 超时时间（单位:s）

            ]
        ];

        $context = stream_context_create($options);

        $result = file_get_contents($url, false, $context);

        return $result;
    }

    public static function curlPost($url, $data)
    {
        $ch                             = curl_init();
        $params[CURLOPT_URL]            = $url;    //请求url地址
        $params[CURLOPT_HEADER]         = FALSE; //是否返回响应头信息
        $params[CURLOPT_SSL_VERIFYPEER] = false;
        $params[CURLOPT_SSL_VERIFYHOST] = false;
        $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
        $params[CURLOPT_POST]           = true;
        $params[CURLOPT_POSTFIELDS]     = $data;
        curl_setopt_array($ch, $params); //传入curl参数
        $content = curl_exec($ch); //执行
        curl_close($ch); //关闭连接
        return $content;
    }

    public static function wechatCurlPost($url, $data, $method = "POST")
    {
        $config = Config::get('wechat_dai');
        // 商户相关配置，
        $merchantId           = $config['merchantId']; // 商户号
        $merchantSerialNumber = $config['merchantSerialNumber']; // 商户API证书序列号
        $merchantPrivateKey   = PemUtil::loadPrivateKey($config['merchantPrivateKey']); // 商户私钥文件路径

        // 微信支付平台配置
        $wechatpayCertificate = PemUtil::loadCertificate($config['wechatpayCertificate']); // 微信支付平台证书文件路径

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware = WechatPayMiddleware::builder()
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)// 传入商户相关配置
            ->withWechatPay([$wechatpayCertificate])// 可传入多个微信支付平台证书，参数类型为array
            ->build();

        // 将WechatPayMiddleware添加到Guzzle的HandlerStack中
        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');

        // 接下来，正常使用Guzzle发起API请求，WechatPayMiddleware会自动地处理签名和验签
        try {
            // 创建Guzzle HTTP Client时，将HandlerStack传入，接下来，正常使用Guzzle发起API请求，WechatPayMiddleware会自动地处理签名和验签
            $client = new Client(['handler' => $stack]);
            if ($method == 'POST') {
                $resp = $client->request($method, $url, [
                    'json'    => $data,
                    'headers' => ['Accept' => 'application/json', 'Accept' => '*/*']
                ]);
            } else {
                $resp = $client->request('GET', $url, [
                    'headers' => ['Accept' => 'application/json']
                ]);
            }
            return json_decode($resp, true);
        } catch (RequestException $e) {
            // 进行错误处理
            $res['code']    = $e->getResponse()->getStatusCode();
            $res['content'] = json_decode($e->getResponse()->getBody(), true);
            return $res;
        }
    }

    public static function RfdCpn($coupon_code)
    {
        Db::startTrans();
        try {
            CouponCodes::where('coupon_code', $coupon_code)->update(['status' => 4]);
            CouponCodeOrderDetail::where('coupon_code', $coupon_code)->update(['status' => 4]);
            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
        }
        $data['code'] = '200';
        $data['msg']  = '退券成功';
        return $data;
    }

    /**
     * 批量加入分配
     * @$arr 数组
     * @$key  字段名
     */
    public static function couponTo($coupon_id)
    {
        $data = CouponCodeGoods::where('1=1')->select();
        foreach ($data as $k => $v) {
            $coupon = $v['coupon_id'] . ',' . $coupon_id;
            CouponCodeGoods::where('id', $v['id'])->update(['coupon_id' => $coupon]);

        }
        return $data;
    }

    /**
     * 批量删除内容中特殊字符串
     * @$arr 数组
     * @$key  字段名
     */
    public static function contentTo($content)
    {
        $data = CouponCodeGoods::where('1=1')->select();
        foreach ($data as $k => $v) {
            $string = str_replace($content, '', $v['describe']);
            if ($v['id'] == 600) {
                var_dump($string);
            }
            CouponCodeGoods::where('id', $v['id'])->update(['describe' => $string]);

        }
        return $data;
    }

    /**
     * 创建微信支付代金券
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function createWeChatPayCashCoupon($requestAllData)
    {
        $config = Config::get('wechat_dai');
        // 商户相关配置，
        $merchantId           = $config['merchantId']; // 商户号
        $merchantSerialNumber = $config['merchantSerialNumber']; // 商户API证书序列号
        $merchantPrivateKey   = PemUtil::loadPrivateKey($config['merchantPrivateKey']); // 商户私钥文件路径

        // 微信支付平台配置
        $wechatpayCertificate = PemUtil::loadCertificate($config['wechatpayCertificate']); // 微信支付平台证书文件路径

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware = WechatPayMiddleware::builder()
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)// 传入商户相关配置
            ->withWechatPay([$wechatpayCertificate])// 可传入多个微信支付平台证书，参数类型为array
            ->build();
        // 将WechatPayMiddleware添加到Guzzle的HandlerStack中
        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');
        $client = new Client(['handler' => $stack]);
        try {
            $resp = $client->request('GET', 'https://api.mch.weixin.qq.com/v3/...', [ // 注意替换为实际URL
                                                                                      'headers' => ['Accept' => 'application/json']
            ]);

            echo $resp->getStatusCode() . ' ' . $resp->getReasonPhrase() . "\n";
            echo $resp->getBody() . "\n";

            $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/...', [
                'json'    => [ // JSON请求体
                               'field1' => 'value1',
                               'field2' => 'value2'
                ],
                'headers' => ['Accept' => 'application/json']
            ]);

            echo $resp->getStatusCode() . ' ' . $resp->getReasonPhrase() . "\n";
            echo $resp->getBody() . "\n";
        } catch (RequestException $e) {
            // 进行错误处理
            echo $e->getMessage() . "\n";
            if ($e->hasResponse()) {
                echo $e->getResponse()->getStatusCode() . ' ' . $e->getResponse()->getReasonPhrase() . "\n";
                echo $e->getResponse()->getBody();
            }
            return;
        }
    }

    public static function CashCouponList($mobile)
    {
        $rest = CouponCodeOrderDetail::where('mobile', $mobile)
            ->alias('a')
            ->join('coupon_codes c', 'c.coupon_code_psd = a.coupon_code_psd')
            ->join('coupon_code_category w', 'w.id =c.coupon_code_category_id')
//            ->where('c.status', 1)
            ->where('w.flag', 14)
            ->field('a.id,a.coupon_code,a.coupon_code_psd,c.status,c.couponprice,a.end_time,w.name')
            ->order('id desc')
            ->select();
        return $rest;
    }
}


